#include <jni.h>
#include <string>
#include <android/log.h>
#include <malloc.h>
#include <string.h>
#include "gif_lib.h"
#include "config.h"
#include "gif_hash.h"
#include "gif_lib_private.h"
#include <android/bitmap.h>

#define   LOGD(...) __android_log_print(ANDROID_LOG_INFO,"jinx",__VA_ARGS__)

std::string jstr2str(JNIEnv *env, jstring jstr) {
    if (jstr == NULL) {
        return "";
    }
    char *rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("UTF-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen <= 0) return "";
    rtn = (char *) malloc(alen + 1);
    memcpy(rtn, ba, alen);
    rtn[alen] = 0;
    std::string stemp(rtn);
    free(rtn);
    env->ReleaseByteArrayElements(barr, ba, 0);
    if (strencode != NULL) {
        env->DeleteLocalRef(strencode);
    }
    if (clsstring != NULL) {
        env->DeleteLocalRef(clsstring);
    }
    return stemp;
}

extern "C" JNIEXPORT jstring JNICALL
Java_pzl_gif_loader_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}


extern "C" JNIEXPORT jlong JNICALL
Java_pzl_gif_loader_Loader_open(
        JNIEnv *env,
        jclass /* this */, jstring filePath) {
    std::string path = jstr2str(env, filePath);
    LOGD("hello =  %s", path.c_str());
    int ErrorCode = 0;
    GifFileType *gifFileType = DGifOpenFileName(path.c_str(), &ErrorCode);
    LOGD("ErrorCode =  %d", ErrorCode);
    ErrorCode = DGifSlurp(gifFileType);
    LOGD("ErrorCode =  %d", ErrorCode);
    int width = gifFileType->SWidth;
    int height = gifFileType->SHeight;
    LOGD("文件 宽 = %d ，高 = %d", width, height);
    int frame = gifFileType->ImageCount;
    LOGD("文件 帧数 = %d ", frame);
    return reinterpret_cast<jlong>(gifFileType);
}

extern "C" JNIEXPORT jint JNICALL
Java_pzl_gif_loader_Loader_getWidth(
        JNIEnv *env,
        jclass /* this */, jlong address) {

    return ((GifFileType *)address)->SWidth;
}

extern "C" JNIEXPORT jint JNICALL
Java_pzl_gif_loader_Loader_getHeight(
        JNIEnv *env,
        jclass /* this */, jlong address) {

    return ((GifFileType *)address)->SHeight;
}

extern "C" JNIEXPORT jint JNICALL
Java_pzl_gif_loader_Loader_getFrameCount(
        JNIEnv *env,
        jclass /* this */, jlong address) {

    return ((GifFileType *)address)->ImageCount;
}

#define delay(ext) (10 *((ext) -> Bytes[2] << 8 | (ext) ->Bytes[1]))

int drawFrame(GifFileType *gif, AndroidBitmapInfo *info, int *pixels, int frame_no) {
    GifColorType *color;
    //每一帧图片
    SavedImage *frame;
    //扩展快，定义一些行为
    ExtensionBlock *ext = 0;
    //描述文件
    GifImageDesc *frameInfo;
    //颜色表
    ColorMapObject *colorMap;
    int *line;
    int  x, y, j, loc;
    int *px;
    //获取这一帧
    frame = &(gif->SavedImages[frame_no]);
    //这一帧相关的描述文件，虽然描述文件已经在GifFileType里面声明了，但是没有赋值
    //所以需要用这种方式
    frameInfo = &(frame->ImageDesc);

    //这一帧的颜色列表
    if (frameInfo->ColorMap) {
        colorMap = frameInfo->ColorMap;
    } else {
        //没有的话就获取全局的颜色列表
        colorMap = gif->SColorMap;
    }

    //遍历这一帧的扩展块，找到具有GRAPHICS_EXT_FUNC_CODE标志位的，这个扩展快存放着对该帧图片的
    //处置方法，是不处理还是其他
    for (j = 0; j < frame->ExtensionBlockCount; ++j) {
        if (frame->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {
            ext = &(frame->ExtensionBlocks[j]);
            break;
        }
    }
    //这时候px是二维指针
    px = pixels;
    //frameInfo->Top：从哪个y坐标开始（距离顶部的top），乘以每一行的字节，就是我们需要开始遍历的字节
    px = (int *) ((char *) px + info->stride * frameInfo->Top);
    //遍历y
    for (y = frameInfo->Top; y < frameInfo->Top + frameInfo->Height; ++y) {
        //行
        line = px;
        //遍历x
        for (x = frameInfo->Left; x < frameInfo->Left + frameInfo->Width; ++x) {
            //当前的这一点
            loc = (y - frameInfo->Top) * frameInfo->Width + (x - frameInfo->Left);
            //判断处置方法，拿到当前帧loc位置的字节，看是否等于扩展块中索引为3的字节，并且数值为1
            if (frame->RasterBits[loc] == ext->Bytes[3] && ext->Bytes[0]) {
                continue;
            }
            color =  &colorMap->Colors[frame->RasterBits[loc]];
            line[x] = ((255 & 0xff)<< 24) | ((color->Blue & 0xff)<< 16) | ((color->Green)<< 8) | (color->Red);
        }
        px = (int *) ((char *) px + info->stride);
    }
    return delay(ext);
}

extern "C" JNIEXPORT jlong JNICALL
Java_pzl_gif_loader_Loader_render(
        JNIEnv *env,
        jclass /* this */, jlong address,jobject jBitmap,jint frameIndex) {

    GifFileType *gifFileType = (GifFileType *) address;
    //bitmap转成颜色矩阵
    void *pixels;
    AndroidBitmapInfo info;
    int err;
    if ((err = AndroidBitmap_getInfo(env, jBitmap, &info)) < 0) {
        return -1;
    }
    //也可以不判断，这里的格式需要有透明通道
    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        return -1;
    }
    //&pixels为指针的指针，即二维数组
    if ((err = AndroidBitmap_lockPixels(env, jBitmap, &pixels)) < 0) {
        return -1;
    }
    //渲染
    long delay_time = drawFrame(gifFileType, &info, (int *) pixels, frameIndex);
    AndroidBitmap_unlockPixels(env, jBitmap);
    return delay_time;

}



